<?php
class Bizonylat extends AppModel {

	var $name = 'Bizonylat';
	var $validate = array(
		'naplo_id' => array('numeric'),
		'osztaly_id' => array('numeric'),
		'user_id' => array('numeric'),
		'sorszam' => array('numeric'),
		'arfolyam' => array('rule' => array('custom', '/\d+[\.\,]?\d{0,2}/')),	//custom esetén a rule nem hagyható el
		'megjegyzes' => array(
									'rule' => array('custom', '/[\w\s\(\)\+\-]/'),
									'allowEmpty' => true),		//szám, betű, _, szóköz, ()+- vagy üres
		'datum' => array('rule' => array('custom', '/\d{4}-\d{2}-\d{2}/'))
		//'hatarido' => array('custom', '/\d{4}/')
	);

	var $belongsTo = array(
			'Naplo' => array('className' => 'Naplo',
								'foreignKey' => 'naplo_id',
								'conditions' => '',
								'fields' => '',
								'order' => ''
			),
			'Osztaly' => array('className' => 'Osztaly',
								'foreignKey' => 'osztaly_id',
								'conditions' => '',
								'fields' => '',
								'order' => ''
			),
			'User' => array('className' => 'User',
								'foreignKey' => 'user_id',
								'conditions' => '',
								'fields' => array('id', 'nev'),	//a passt nem kérjük itt le
								'order' => ''
			)
	);

	var $hasMany = array(
			'Tetel' => array('className' => 'Tetel',
								'foreignKey' => 'bizonylat_id',
								'dependent' => false,
								'conditions' => '',
								'fields' => '',
								'order' => '',
								'limit' => '',
								'offset' => '',
								'exclusive' => '',
								'finderQuery' => '',
								'counterQuery' => ''
			)
	);

	function elokeszit($data){
/*debug($data);die();/*
$data
Array
(ev, cegId, userCsoport
    [Tetel] => Array
        (
            [0] => Array
                (
                    [osszeg] => 23000
                    [szoveg] => 1 db toll
                    [account] => 1570
                    [gyujto] => Array
                        (
                            [0] => 89
                            [1] => 43
                        )

                )

        )

    [Bizonylat] => Array
        (
            [_method] => POST
            [bizonylat_id] => 2542		//módosítás
            [naplo_id] => 2
            [user_id] => 1
            [arfolyam] => 1			[arfolyam] => 311,11
            [sorszam] => 17
            [osztaly_id] => 2
            [irany] => k
            [datum] => 2008-12-31
            [megjegyzes] => 2. elszámoló lap
        )

)

vegyesnél:
Array
(
    [Tetel] => Array
        (
            [0] => Array
                (
                    [osszeg] => 15
                    [szoveg] => helyesbítés
                    [accountT] => 265
                    [accountK] => 268
                )

        )

    [Bizonylat] => Array
        (
            [_method] => POST
            [naplo_id] => 91
            [user_id] => 1
            [sorszam] => 19
            [datum] => 2009-10-29
            [osztalytol] => 12 Controlling
            [osztaly_id] => 3
            [megjegyzes] => bizonylat megjegyzése))
*/
		//0. dátum
		//a könyvelési év megegyezik a bizonylat évével?
		if(!$this->isDatesInSameYear($data)){
			throw new BadRequestException('Sikertelen mentés: A ' . $data['Bizonylat']['datum'] . ' dátum nem a jelenlegi könyvelési évben ('.$data['ev'].') van!');
			return false;
		}
		
		//ellenőrizzük, hogy a dátum nem lezárt időszakhoz tartozik-e
		if(!$this->isLezartDate($data)){
			throw new BadRequestException('Sikertelen mentés: A ' . $data['Bizonylat']['datum'] . ' dátumra már nem lehet könyvelni, az időszak le van zárva!');
			return false;
		}
		
		//monoton?
		if(!$this->isMonoton($data)){
			throw new BadRequestException('Sikertelen mentés: A ' . $data['Bizonylat']['datum'] . ' dátumra már nem lehet könyvelni, az időszak le van zárva!');
			return false;
		}

		//nincsen tétel a bizonylaton
		if(!isset($data['Tetel'])){
			throw new BadRequestException('Sikertelen mentés: Nincs tétel a bizonylatban!');
			return false;
		}

		//1. az irány alapján a tételek tömbben az account kulcsokat cserélni kell t-re vagy k-ra
		$irany = (isset($data['Bizonylat']['irany'])) ? $data['Bizonylat']['irany'] : null;
		unset($data['Bizonylat']['irany']);

		$data['Tetel'] = $this->gyujtoAtalakit($data['Tetel']);

		//3. ha van illesszük be az alapértelmezett számla kódot. ha nincs akkor a $alapSzamla = 1
		$alapSzamla = $this->Naplo->field('alapertelmezett_szamla', array('id' => $data['Bizonylat']['naplo_id']));

		//4. árfolyam kezelés
		App::uses('SzamKezelo', 'Utility');
		$szamKezelo = new SzamKezelo();
		//ha az árfolyam nem 1 akkor át kell számítani
		if(isset($data['Bizonylat']['arfolyam']) && intval($data['Bizonylat']['arfolyam']) != 1){
			$arfolyam = $szamKezelo->floatFromString($data['Bizonylat']['arfolyam']);
			$data['Bizonylat']['arfolyam'] = $arfolyam;
			}
		else
			$arfolyam = false;

		$tetelszam = count($data['Tetel']);
		for($i = 0; $i < $tetelszam; $i++){
			//4. a bizonylaton belüli tétel sorszám hozzáadása
			$data['Tetel'][$i]['sorszam'] = $i;

			//5. ha a form sorából (is) küldtünk adatot (számla nevet és számot kaptuk nem a id-t) akkor ki kell keresni a számla id-jét
			$params = array('cegId' => $data['cegId'], 'ev' => $data['ev']);
			if(isset($data['tipus']) && $data['tipus'] == 'import')
				$params['szamlaSzam'] = true;		//kapunk számlaszámot szöveg nélkül id helyett importnál

			if($irany){
				$data['Tetel'][$i]['account'] = $this->Tetel->TartozikSzamla->getSzamlaId($data['Tetel'][$i]['account'], $params);
			}
			else{
				$data['Tetel'][$i]['accountT'] = $this->Tetel->TartozikSzamla->getSzamlaId($data['Tetel'][$i]['accountT'], $params);
				$data['Tetel'][$i]['accountK'] = $this->Tetel->TartozikSzamla->getSzamlaId($data['Tetel'][$i]['accountK'], $params);
			}

			//6. A főkönyvi oldalak beállítása
			if($irany == 'b'){	//bevételnek jelölt, tartozik a pénztár/bank
				$data['Tetel'][$i]['t'] = $alapSzamla;
				$data['Tetel'][$i]['k'] = $data['Tetel'][$i]['account'];
				unset($data['Tetel'][$i]['account']);
			}
			elseif($irany == 'k'){	//kiadásnak jelölt, tartozik a tétel számlája
				$data['Tetel'][$i]['t'] = $data['Tetel'][$i]['account'];
				$data['Tetel'][$i]['k'] = $alapSzamla;
				unset($data['Tetel'][$i]['account']);
			}
			else{
				//vegyes bizonylat nincs irány
				$data['Tetel'][$i]['t'] = $data['Tetel'][$i]['accountT'];
				$data['Tetel'][$i]['k'] = $data['Tetel'][$i]['accountK'];
				unset($data['Tetel'][$i]['accountT'], $data['Tetel'][$i]['accountK']);
			}

			//7. az összeg átalakítása
			$data['Tetel'][$i]['osszeg'] = $szamKezelo->floatFromString($data['Tetel'][$i]['osszeg']);
			if($arfolyam){
				//valutás tétellel van dolgunk adjuk hozzá tételenként a valutatételek tömböt
				$data['Tetel'][$i]['Valutatetel'] = array(
																			'osszeg' => $data['Tetel'][$i]['osszeg'],
																			'arfolyam' => $arfolyam,
																			'valuta_id' => $this->Naplo->getValutaId($data['Bizonylat']['naplo_id'])
																			);
				if(isset($data['Tetel'][$i]['id']))
					$data['Tetel'][$i]['Valutatetel']['tetel_id'] = $data['Tetel'][$i]['id'];
				$data['Tetel'][$i]['osszeg'] = round($arfolyam * $data['Tetel'][$i]['osszeg'], 0);
			}
		}
//Debugger::log($data);
/*die(debug($data));
/*$data
Array
(
    [Tetel] => Array
        (
            [0] => Array
                (
                    [osszeg] => 23000
                    [szoveg] => 1 db toll
                    [gyujto] => Array
                        (
                            [0] => 89
                            [1] => 43
                        )

                    [sorszam] => 0
                    [t] => 1570
                    [k] => 1421

                    [Valutatetel] => Array
                        (
                            [osszeg] => 11.11
                            [arfolyam] => 311.11
                            [valuta_id] => 2)))
    [Bizonylat] => Array
        (
            [_method] => POST
            [naplo_id] => 2
            [user_id] => 1
            [arfolyam] => 1
            [sorszam] => 17
            [osztaly_id] => 2
            [datum] => 2008-12-31
            [megjegyzes] => 2. elszámoló lap))
*/
	return $data;
	}

/**
 * a könyvelési év megegyezik a bizonylat évével?
 * @param array $data a formmal elküldött adatok
 * @return bool true on success
 */
	function isDatesInSameYear($data){
		if($data['ev'] == substr($data['Bizonylat']['datum'], 0, 4)){
			return true;
		}
		return false;
	}

/**
 * a dátum nem lezárt időszakot érint-e
 * @param array $data a formmal elküldött adatok
 * @return bool true on success
 */
	function isLezartDate($data, $ignoreForAdmin = true){
		$utsoLezart = $this->getLastLezart(array(
											'ev' => $data['ev'],
											'cegId' => $data['cegId']));
		
		if($ignoreForAdmin){
			if($utsoLezart && $data['Bizonylat']['datum'] <= $utsoLezart && $data['userCsoport'] > 1){
				return false;
			}
			else
				return true;
		}
		else{
			if($utsoLezart && $data['Bizonylat']['datum'] <= $utsoLezart){
				return false;
			}
			else
				return true;
		}
	}

/**
 * a dátum monoton?
 * @param array $data a formmal elküldött adatok
 * @return bool true on success
 */
	function isMonoton($data){
		$lastDatum = isset($data['Bizonylat']['bizonylat_id'])
				? $this->getLastFromNaplo($data['Bizonylat']['naplo_id'], $data['Bizonylat']['bizonylat_id'])
				: $this->getLastFromNaplo($data['Bizonylat']['naplo_id']);
		if($data['Bizonylat']['datum'] >= $lastDatum['datum']){
			return true;
		}
		return false;
	}
	
/**
 * Új bizonylat rögzítése
 * ha a saveAll metódus több mint egy szintet és HABTM kapcsolatokat is tudna menteni akkor
 * szükségtelenné válna
 * @param array $data a formmal elküldött adatok
 * @param array $settings a sessionban tárol beállítások, mint cegId és ev
 * @param bool $startTransaction indítsunk-e tranzakciót vagy már fut?
 * @return bool sikeres a mentés vagy nem
 */
	function rogzit($data, $settings, $startTransaction = true){
		//Debugger::log($data);
		//első lépésben mentjük a bizonylatot
		$bizonylat = array();
		$bizonylat['Bizonylat'] = $data['Bizonylat'];
		//tranzakció kezdődik
		if($startTransaction)
			$this->query('START TRANSACTION');
		if($this->save($bizonylat)){
			//a tételekhez betesszük a bizonylat id-jét
			$bizonylatId = $this->id;
			//az ojjektumból meg eltávolítjuk, hogy ha ciklusban hívjuk a rogzitet (pl bemiport) akkor ne update-et hanem insertet csináljon
			$this->id = null;

			//menjünk végig a tételek tömbön és mentsük a tételeket a gyüjtőkkel együtt
			foreach($data['Tetel'] as $tetel){
				//illeszük be a Tetel kulcsot mint modellnevet a tömb elejére a cake konvenciók szerint
				//ezt azért nem a view-ben csináljuk meg, mert így egyszerűbb kezelni a nézetet és a js-t
				$t = array();
				$t['Tetel'] = $tetel;
				$t['Tetel']['bizonylat_id'] = $bizonylatId;

				if(isset($t['Tetel']['gyujto'])){
					$gyujto = $t['Tetel']['gyujto'];
					unset($t['Tetel']['gyujto']);
					$t['Gyujto']['Gyujto'] = array();	//ahhoz szükséges, hogy ha módosításkor töröljük az összes gyüjtőt és nem marad akkor lássa, hogy kell módosítani
					foreach($gyujto as $gy){
						//konvenciók szerinti átalakítás
						$t['Gyujto']['Gyujto'][] = $gy;
					}
				}

				//a valutatétel tömb átalakítása
				if(isset($t['Tetel']['Valutatetel'])){
					$t['Valutatetel'] = $t['Tetel']['Valutatetel'];
					unset($t['Tetel']['Valutatetel']);
				}

				//Debugger::log($t);
				//saveallt hívunk, hogy a valuta tétel is mentődjön
				$this->Tetel->create($t);
				if($this->Tetel->saveAll($t)){
					//az id-t nullra kell állítani, hogy a foreach következő lépésében is insert legyen update helyett
					$this->Tetel->id = null;

					//egyenlegek frissítése
					//a modellek nem látják egymást, ezért kézzel be kell tölteni a számlaegyenleg modelt
					App::import('Model', 'Szamlaegyenleg');
					$szamlaegyenleg = new Szamlaegyenleg();
					$tetel['osztalyId'] = $bizonylat['Bizonylat']['osztaly_id'];	//a $szamlaegyenleg->frissit függvény igényli ezt a kulcsot
					//debug($tetel);
					if(!$szamlaegyenleg->frissit($tetel, $settings)){
						if($startTransaction)
							$this->query('ROLLBACK');
						//Debugger::log($tetel);
						//debug($tetel);
						//die('!$szamlaegyenleg->frissit($tetel, $settings)');
						return false;
					}
				}
				else{		//a tétel nem volt menthető
					if($startTransaction)
						$this->query('ROLLBACK');
					//Debugger::log($t);
					//debug($t);
					//die('$this->Tetel->save($t)');
					return false;
				}
			}
		}
		else{		//a bizonylat nem volt menthető
			if($startTransaction)
				$this->query('ROLLBACK');
			//Debugger::log($bizonylat);
			//Debugger::log($this->validationErrors);
			return false;
		}
		if($startTransaction)
			$this->query('COMMIT');
		return true;
	}

/**
 * Utolsó lezárt bizonylat dátuma
 *
 * @param array $params
 * 					ev			melyik évben keresgéljünk
 * 					cegId		melyik cégben keresgéljünk
 * @return date az utolsó lezárt hónap utolsó napja vagy false ha nincs még lezárva semmi
*/
	function getLastLezart($params){
		if(!$params['ev'] || !$params['cegId'])
			throw new NotImplementedException('Hiányzik az Bizonylat->getLastLezart hívásnál az év vagy a cegId!');

		$this->unbindModel(array('hasMany' => array('Tetel'), 'belongsTo' => array('User', 'Naplo')));
		$this->bindModel(array('hasOne' => array(
											'GyujtoOsztaly' => array(
																		'foreignKey' => false,
																		'type' => 'INNER',
																		'conditions' => array('GyujtoOsztaly.osztaly_id = Osztaly.id')
																		),
											'Gyujto' => array(
																		'foreignKey' => false,
																		'type' => 'INNER',
																		'conditions' => array(
																									'Gyujto.id = GyujtoOsztaly.gyujto_id',
																									'Gyujto.id' => $params['cegId']
																									)
																	)
											)
						));

		$utolsolezart = $this->find('first', array(
															'fields' => 'datum',
															'conditions' => array(
																					'Bizonylat.zarolt' => true,
																					'Bizonylat.datum >=' => $params['ev'] . '-01-01',
																					'GyujtoOsztaly.gyujto_id' => $params['cegId']),
															'order' => 'Bizonylat.datum DESC'));
		if($utolsolezart)
			$utolsolezart = date('Y-m-t', strtotime($utolsolezart['Bizonylat']['datum']));	//utolsó nap a hónapban
		return $utolsolezart;
	}


/**
 * Utolsó bizonylat az adott naplóban
 *
 * @param int naploId a kérdéses napló id-je amiben keressük az utolsó bizonylat sorszámát
 * @param int bionylatId-nél korábbi bizonlatokat keresünk (módosításnál)
 * @return int az utolsó bizonylat sorszáma
*/
	function getLastFromNaplo($naploId, $bizonylatId = null){
		$conditions = array('Bizonylat.naplo_id' => $naploId);
		if($bizonylatId)
			$conditions['Bizonylat.id <'] = $bizonylatId;
		$sorszam = $this->find('first',
											array(
													'order' => 'sorszam DESC',
													'recursive' => -1,
													'conditions' => $conditions));
		if($sorszam)
//TODO: elég lenne ha csak a sorszámot adná át nem az egész bizonlatot
			return $sorszam['Bizonylat'];
		else
			return 0;
	}

/* ha a form sorából (is) küldtünk adatot át kell alakítani a gyüjtőket
 * data[Tetel][0][gyujto]	Sripati d jön data[Tetel][0][gyujto][]	104 helyett, azaz stringet kaptunk nem tömböt
 * vagy olyan tömböt kapunk aminek az utolsó eleme nem szám hanem string (le is volt küldve gyüjtő s a formból is jött)
 * 	data[Tetel][0][gyujto][]	5
 * 	data[Tetel][0][gyujto][]	Raghunatha d
 * 	
 * @param array $tetel a tételek tömbje
 * @return array az átalakított gyüjtőkkel megáldott tömb
 */
	function gyujtoAtalakit($tetel){
		//debug($tetel);
		if(!isset($tetel[0])){	//egy dimenziós tömb van, egy tételsorról van szó
			$_tetel = $tetel;
			unset($tetel);
			$tetel = array($_tetel);
		}
		foreach($tetel as $index => $t){
			if(!isset($t['gyujto'])){
				$tetel[$index]['gyujto'] = array();
			}
			else{
				if(is_array($t['gyujto'])){
					foreach($t['gyujto'] as $i => $gy){
						if(!is_numeric($gy)){
							$tetel[$index]['gyujto'][$i] = $this->Tetel->Gyujto->getIdByNev($gy);
						}
					}
				}
				elseif(!is_numeric($t['gyujto'])){
					$tetel[$index]['gyujto'] = array($this->Tetel->Gyujto->getIdByNev($t['gyujto']));
				}
				elseif(is_numeric($t['gyujto'])){
					$tetel[$index]['gyujto'] = array($t['gyujto']);
				}
			}
		}
		if(isset($_tetel))
			$tetel = $tetel[0];
		return $tetel;
	}
}
?>
